#include<noise/ChunkGenerator.h>
#include<Chunk/Chunk.h>
#include <algorithm>
#include <MCWorld.h>

siv::PerlinNoise ChunkGenerator::Generator::RiverPerlinNoise(MCWorld::GetSeed());

ChunkGenerator::Generator * ChunkGenerator::CreateGenerator(
    uint32_t seed,uint32_t chunkType)
{
    switch (chunkType)
    {
    case ChunkType::Plain:
        return ChunkGenerator::Plain::Instance(seed);
    default:
        return nullptr;
    }
    return nullptr;
}

float ChunkGenerator::Generator::GenerateRiverNoise(int x, int y)
{
    float res = RiverPerlinNoise.octave2D_01(x/16.f, y/16.f, 4);
    res = std::tanh(res *8.f - 5.f)/2.f + 0.5f; 
    return res * -8.f;
}



ChunkGenerator::Plain::Plain(uint32_t Seed):Generator(Seed),HeightPerlinNoise(Seed)
{
    
}

void ChunkGenerator::Plain::Generate(ChunkBlocksVector& blocks,int ChunkX, int ChunkY)
{
    for (int x = 0; x < 16; x++)
    {
        for (int y = 0; y < 16; y++)
        {
            int realx = ChunkX * 16 + x;
            int realy = ChunkY * 16 + y;
            uint8_t high = GenerateAltitude(realx, realy);

            blocks[x][y][0] = new Bedrock_Block();

            blocks[x][y][0]->SetBrightnessLevel_face(BlockBase::faceid::ALL, 15);

            if(high>= this->SeaLevelHeight)
            {
                int z = 1;
                for (; z < int(high)-4 && z; z++)
                {
                    blocks[x][y][z] = new RoughStone_Block();
                    blocks[x][y][z]->SetBrightnessLevel_face(BlockBase::faceid::ALL, 15);
                }
                for (; z < int(high)-1; z++)
                {
                    blocks[x][y][z] = new Dirt_Block();
                    blocks[x][y][z]->SetBrightnessLevel_face(BlockBase::faceid::ALL, 15);
                }
                blocks[x][y][z] = new GrassDirt_Block();
                blocks[x][y][z]->SetBrightnessLevel_face(BlockBase::faceid::ALL, 15);

            }
            else
            {   
                int z = 1;
                for (; z < int(high); z++)
                {
                    blocks[x][y][z] = new RoughStone_Block();
                    blocks[x][y][z]->SetBrightnessLevel_face(BlockBase::faceid::ALL, 15);
                }
                for(;z<this->SeaLevelHeight;z++)
                {
                    blocks[x][y][z] = new Sand_Block();
                    blocks[x][y][z]->SetBrightnessLevel_face(BlockBase::faceid::ALL, 15);
                }


            }

            // int z = 1;
            // for (; z < int(high)-4 && z < this->SeaLevelHeight ; z++)
            // {
            //     blocks[x][y][z] = new Stone_Block();
            //     blocks[x][y][z]->SetBrightnessLevel_face(Block::faceid::ALL, 15);
            // }

            // for (; z < int(high)-1; z++)
            // {
            //     blocks[x][y][z] = new Dirt_Block();
            //     blocks[x][y][z]->SetBrightnessLevel_face(Block::faceid::ALL, 15);
            // }
            // blocks[x][y][z] = new GrassDirt_Block();
            // blocks[x][y][z]->SetBrightnessLevel_face(Block::faceid::ALL, 15);
        }
    } 

}
uint8_t ChunkGenerator::Plain::GenerateAltitude(int x ,int y)
{
    float height = this->HeightPerlinNoise.octave2D_01(x/32.f, y/32.f, 8)  * 8 
                + this->SeaLevelHeight;

    height += this->GenerateRiverNoise(x, y);


    return std::clamp(height,0.0f, 255.0f);
}

